/*******************************************************************/
/* @ All Rights Reserved Copyright (C) 2014 broada,Co.,Ltd.        */
/*                                                                 */
/*  NAME      = frexp_comm.c                                       */
/*  NOTE      = 关联连接共通管理                                   */
/*  DATE      = 2015/07/27 yaohl                                   */
/*******************************************************************/

#include "frcomm.h"
#include "frhash2.h"
#include "frlog.h"

#include "conntrack.h"
#include "module.h"

#include "frvar_field.h"
#include "frexp_comm.h"

int frexpect_hash_key(u_short us_proto
                    , u_int ui_src_ip
                    , u_short us_src_port
                    , u_int ui_dst_ip
                    , u_short us_dst_port
                    , char *p_key
                    , unsigned int ui_key_size)
{
    int i_idx=0, i_len;
    u_int *stupid_strict_aliasing_warnings=(u_int*)p_key;

    if(p_key == NULL || ui_key_size <= sizeof(u_int)*2+ sizeof(u_short)*3)
    {
        FRLOG_ERROR_DETAIL("expect hash key err");
        return 0;
    }

    i_len = sizeof(u_int);
    *stupid_strict_aliasing_warnings = ui_src_ip;
    i_idx += i_len;

    *(u_int *) (p_key + i_idx) = ui_dst_ip;
    i_idx += i_len;

    i_len = sizeof(u_short);
    *(u_short *) (p_key + i_idx) = us_src_port;
    i_idx += i_len;

    *(u_short *) (p_key + i_idx) = us_dst_port;
    i_idx += i_len;

    *(u_short *) (p_key + i_idx) = us_proto;
    i_idx += i_len;

    return i_idx;
}

/*******************************************************************************
*  FUNC     :  增加关联连接
*  ARGS     :  p_frame_ref  (框架引用信息)
*           :  us_proto     (协议 tcp/udp)
*           :  ui_src_ip    (原地址, 没有设置为0)
*           :  us_src_port  (原port，没有设置为0)
*           :  ui_dst_ip    (目的地址)
*           :  us_dst_port  (目的port)
*           :  us_stat_src_port  (统计用原port，没有设置为0)
*           :  us_state_dst_port (统计用目的port，没有设置为0)
*           ：  i_l7_proto   (l7协议号,没有设置为0)
*           :  p_lst_hdr_param    (Frlist_header, 传递到子连接的参数, 没有设置为NULL)
*           :  p_st_ct      (Conntrack *)
*  RTN      :  FR_SUCC:成功, FR_FAIL:失败
*  NOTE     :
*******************************************************************************/
FR_STATIC int __frexpect_add(Frexp_ref* p_st_expRef
                           , u_short us_proto
                           , u_int ui_src_ip
                           , u_short us_src_port
                           , u_int ui_dst_ip
                           , u_short us_dst_port
                           , u_short us_stat_src_port
                           , u_short us_stat_dst_port
                           , int i_l7_proto
                           , Frlist_header *p_lst_hdr_param
                           , Conntrack *p_st_ct)
{
    Frlist_node *p_st_node=NULL;
    char arr_hash_key[30];
    int i_hash_key_len=0;
    Frexp *p_st_exp=NULL;
    int i_ret = FR_FAIL, i_ret_fun;

    if(p_st_expRef == NULL || p_st_ct == NULL
       || p_st_expRef->p_hash_hdr == NULL || p_st_expRef->p_splock == NULL)
        return FR_FAIL;

    //确认关联连接是否存在
    i_hash_key_len = frexpect_hash_key(us_proto, ui_src_ip, us_src_port, ui_dst_ip, us_dst_port, arr_hash_key, sizeof(arr_hash_key));
    if(i_hash_key_len <=0)
        return i_ret;

    pthread_spin_lock(p_st_expRef->p_splock);
    p_st_node = frhash2_getStr(p_st_expRef->p_hash_hdr, arr_hash_key, i_hash_key_len);
    //p_st_exp = (Frexp *)FRLIST_GET_NODE_DATA(p_st_node);
    if(p_st_node)
    {
        pthread_spin_unlock(p_st_expRef->p_splock);
        return FR_FAIL;
    }
    else
        pthread_spin_unlock(p_st_expRef->p_splock);

    //增加管理连接
    p_st_exp = (Frexp *)frmalloc(sizeof(Frexp));
    if(!p_st_exp)
        return i_ret;
    memset(p_st_exp, 0x00, sizeof(Frexp));
    p_st_exp->us_proto = us_proto;
    p_st_exp->ui_src_ip = ui_src_ip;
    p_st_exp->us_src_port = us_src_port;
    p_st_exp->ui_dst_ip = ui_dst_ip;
    p_st_exp->us_dst_port = us_dst_port;

    p_st_exp->master_src_ip = p_st_ct->src_ip;
    p_st_exp->master_src_port = p_st_ct->src_port;
    p_st_exp->master_dst_ip = p_st_ct->dst_ip;
    p_st_exp->master_dst_port = p_st_ct->dst_port;

    p_st_exp->stat_src_port = us_stat_src_port;
    p_st_exp->stat_dst_port = us_stat_dst_port;

    gettimeofday (&p_st_exp->st_timeval_upd, NULL);

    if(p_st_ct->st_l7_analyzer.p_st_l7_module)
    {
        p_st_exp->p_master_l7_module = p_st_ct->st_l7_analyzer.p_st_l7_module;
        __sync_fetch_and_add(&p_st_exp->p_master_l7_module->ul_refcnt, 1);
    }

    p_st_exp->i_l7_proto = i_l7_proto;
    p_st_exp->p_lst_hdr_param = p_lst_hdr_param;

    p_st_node = frlist_node_create(p_st_exp);
    if(!p_st_node)
    {
        if(p_st_exp->p_master_l7_module)
            __sync_fetch_and_sub(&p_st_exp->p_master_l7_module->ul_refcnt, 1);
        frfree(p_st_exp);
        return i_ret;
    }

    pthread_spin_lock(p_st_expRef->p_splock);
    i_ret_fun = frhash2_addStr(p_st_expRef->p_hash_hdr, arr_hash_key, i_hash_key_len, p_st_node);
    if(i_ret_fun == FR_FAIL)
    {
        pthread_spin_unlock(p_st_expRef->p_splock);
        if(p_st_exp->p_master_l7_module)
            __sync_fetch_and_sub(&p_st_exp->p_master_l7_module->ul_refcnt, 1);
        if(p_st_node) frfree(p_st_node);
        if(p_st_exp) frfree(p_st_exp);

        return FR_FAIL;
    }
    pthread_spin_unlock(p_st_expRef->p_splock);

    return FR_SUCC;
}


int frexpect_add(void* p_frame_ref ,u_short us_proto, u_int ui_dst_ip, u_short us_dst_port, Conntrack *p_st_ct)
{
    ApmContext *p_apm_context = (ApmContext *)p_frame_ref;

    if(p_frame_ref == NULL || p_st_ct== NULL)
        return FR_FAIL;

    if( p_apm_context->p_st_exp_ref == NULL )
        return FR_FAIL;
    //frwarn("expect_add %s:%i\n", int_ntoa (ui_dst_ip), us_dst_port);
    return __frexpect_add(p_apm_context->p_st_exp_ref
                        , us_proto, p_st_ct->src_ip, 0, ui_dst_ip, us_dst_port
                        , 0, p_st_ct->dst_port
                        , 0, NULL, p_st_ct);
}

int frexpect_add2(void* p_frame_ref
               , u_short us_proto
               , u_int ui_src_ip
               , u_short us_src_port
               , u_int ui_dst_ip
               , u_short us_dst_port
               , u_short us_stat_src_port
               , u_short us_stat_dst_port
               , int i_l7_proto
               , Frlist_header *p_lst_hdr_param
               , Conntrack *p_st_ct)
{
    ApmContext *p_apm_context = (ApmContext *)p_frame_ref;

    if(p_frame_ref == NULL || p_st_ct== NULL)
        return FR_FAIL;

    if( p_apm_context->p_st_exp_ref == NULL )
        return FR_FAIL;

    //frwarn("expect_add %s:%i\n", int_ntoa (ui_dst_ip), us_dst_port);
    return __frexpect_add(p_apm_context->p_st_exp_ref
                        , us_proto, ui_src_ip, us_src_port, ui_dst_ip, us_dst_port
                        , us_stat_src_port, us_stat_dst_port
                        , i_l7_proto, p_lst_hdr_param, p_st_ct);
}


Frlist_header *frexpect_get_param(Conntrack *p_st_ct)
{
    if(p_st_ct == NULL)
        return NULL;
    if(p_st_ct->flg_has_master == FR_NO)
        return NULL;

    Frlist_header *p_lst_hdr_param=NULL;
    p_lst_hdr_param = p_st_ct->st_masterInfo.p_lst_hdr_param;
    p_st_ct->st_masterInfo.p_lst_hdr_param = NULL;
    //逻辑上不存在多线程同时操作的情况,故没有加锁

    return p_lst_hdr_param;
}

/*******************************************************************************
*  FUNC     :  节点内存释放
*  ARGS     :  p_st_node  (Frlist_node *)
*  RTN      :
*  NOTE     :
*******************************************************************************/
FR_STATIC void __list_node_free_param(Frlist_node *p_st_node)
{
    Frvar_field *p_varfiled=NULL;
    if(p_st_node==NULL || p_st_node->data == NULL )
        return;

    p_varfiled = (Frvar_field *)(p_st_node->data);
    frvarfield_free(&p_varfiled);
    p_st_node->data = NULL;

    return;
}

void frexpect_free_param(Frlist_header **pp_list_hdr)
{
    Frlist_header *p_list_hdr=NULL;

    if(pp_list_hdr == NULL || *pp_list_hdr == NULL)
        return;

    p_list_hdr = *pp_list_hdr;
    frlist_destroy(p_list_hdr, __list_node_free_param);
    *pp_list_hdr = NULL;

    return;
}

int frexpect_get_exp_ip(Conntrack *p_st_ct, u_int *p_ui_src_ip, u_short *p_us_src_port, u_int *p_ui_dst_ip, u_short *p_us_dst_port)
{
    if(p_st_ct == NULL || p_st_ct->flg_has_master == FR_NO)
        return FR_FAIL;

    if(p_ui_src_ip)
        *p_ui_src_ip = p_st_ct->st_masterInfo.exp_src_ip;
    if(p_us_src_port)
        *p_us_src_port = p_st_ct->st_masterInfo.exp_src_port;
    if(p_ui_dst_ip)
        *p_ui_dst_ip = p_st_ct->st_masterInfo.exp_dst_ip;
    if(p_us_dst_port)
        *p_us_dst_port = p_st_ct->st_masterInfo.exp_dst_port;

    return FR_SUCC;
}
